<!DOCTYPE html>
<html lang="en">
<head><!-- hexo injector head_begin start -->
        <link rel="preconnect" href="https://blog.fantasyke.cn/picx-images-hosting" crossorigin=""><!-- hexo injector head_begin end -->
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/uploads/avatar.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/uploads/avatar.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <meta name="google-site-verification" content="0qBBGdG7vYORyT5XLZRUqQZ_y5kKYhgyUwNqjSIImg0">
  <meta name="msvalidate.01" content="63C90D0EC3DA6C31FD109132B7BEF502">

<link rel="stylesheet" href="/css/main.css">

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Zen+Maru+Gothic:300,300italic,400,400italic,700,700italic%7CZCOOL+XiaoWei:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha256-5eIC48iZUHmSlSUz9XtjRyK2mzQkHScZY1WdMaoz74E=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.31/fancybox/fancybox.css" integrity="sha256-gkQVf8UKZgQ0HyuxL/VnacadJ+D2Kox2TCEBuNQg5+w=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"blog.fantasyke.cn","root":"/","images":"/images","scheme":"Mist","darkmode":false,"version":"8.21.1","exturl":true,"sidebar":{"position":"right","width_expanded":350,"width_dual_column":240,"display":"post","padding":18,"offset":12},"hljswrap":true,"copycode":{"enable":true,"style":null},"fold":{"enable":true,"height":500},"bookmark":{"enable":true,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":"gitalk","storage":true,"lazyload":true,"nav":{"gitalk":{"text":"gitalk","order":-1}},"activeClass":"gitalk"},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"Searching...","empty":"We didn't find any results for the search: ${query}","hits_time":"${hits} results found in ${time} ms","hits":"${hits} results found"},"path":"/search.xml","localsearch":{"enable":true,"top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content=".NET Core操作Redis 持久化 持久化过程保存什么">
<meta property="og:type" content="article">
<meta property="og:title" content="Redis进阶">
<meta property="og:url" content="https://blog.fantasyke.cn/posts/1297/index.html">
<meta property="og:site_name" content="Fantasy&#39;Ke Blog">
<meta property="og:description" content=".NET Core操作Redis 持久化 持久化过程保存什么">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://fantasy-ke.github.io/picx-images-hosting/redis/image.3nrn361nc4.webp">
<meta property="og:image" content="https://fantasy-ke.github.io/picx-images-hosting/redis/image.491apgw8io.webp">
<meta property="og:image" content="https://fantasy-ke.github.io/picx-images-hosting/redis/image.esj6iefr9.webp">
<meta property="og:image" content="https://fantasy-ke.github.io/picx-images-hosting/redis/image.45horr3f9n.webp">
<meta property="og:image" content="https://fantasy-ke.github.io/picx-images-hosting/redis/image.1hs8heaien.webp">
<meta property="article:published_time" content="2023-05-30T04:08:00.000Z">
<meta property="article:modified_time" content="2024-12-17T06:36:35.395Z">
<meta property="article:author" content="Fantasy-ke">
<meta property="article:tag" content="Redis">
<meta property="article:tag" content="NOSQL">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fantasy-ke.github.io/picx-images-hosting/redis/image.3nrn361nc4.webp">


<link rel="canonical" href="https://blog.fantasyke.cn/posts/1297/">


<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"en","comments":true,"permalink":"https://blog.fantasyke.cn/posts/1297/","path":"posts/1297/","title":"Redis进阶"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Redis进阶 | Fantasy'Ke Blog</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<link rel="alternate" href="/atom.xml" title="Fantasy'Ke Blog" type="application/atom+xml">
<style>.darkmode--activated{--body-bg-color:#282828;--content-bg-color:#333;--card-bg-color:#555;--text-color:#ccc;--blockquote-color:#bbb;--link-color:#ccc;--link-hover-color:#eee;--brand-color:#ddd;--brand-hover-color:#ddd;--table-row-odd-bg-color:#282828;--table-row-hover-bg-color:#363636;--menu-item-bg-color:#555;--btn-default-bg:#222;--btn-default-color:#ccc;--btn-default-border-color:#555;--btn-default-hover-bg:#666;--btn-default-hover-color:#ccc;--btn-default-hover-border-color:#666;--highlight-background:#282b2e;--highlight-foreground:#a9b7c6;--highlight-gutter-background:#34393d;--highlight-gutter-foreground:#9ca9b6}.darkmode--activated img{opacity:.75}.darkmode--activated img:hover{opacity:.9}.darkmode--activated code{color:#69dbdc;background:0 0}button.darkmode-toggle{z-index:9999}.darkmode-ignore,img{display:flex!important}.beian img{display:inline-block!important}</style></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">Fantasy'Ke Blog</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="Search" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>Home</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>Archives</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>About</a></li><li class="menu-item menu-item-photos"><a href="/photos/" rel="section"><i class="fas fa-camera-retro fa-fw"></i>photos</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>Search
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
      <div class="search-header">
        <span class="search-icon">
          <i class="fa fa-search"></i>
        </span>
        <div class="search-input-container">
          <input autocomplete="off" autocapitalize="off" maxlength="80"
                placeholder="Searching..." spellcheck="false"
                type="search" class="search-input">
        </div>
        <span class="popup-btn-close" role="button">
          <i class="fa fa-times-circle"></i>
        </span>
      </div>
      <div class="search-result-container">
        <div class="search-result-icon">
          <i class="fa fa-spinner fa-pulse fa-5x"></i>
        </div>
      </div>
    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-number">1.</span> <span class="nav-text"> .NET Core操作Redis</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#-2"><span class="nav-number">2.</span> <span class="nav-text"> 持久化</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#-3"><span class="nav-number">2.1.</span> <span class="nav-text"> 持久化过程保存什么</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-4"><span class="nav-number">2.2.</span> <span class="nav-text"> RDB</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#-5"><span class="nav-number">2.2.1.</span> <span class="nav-text"> RDB持久化的配置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-6"><span class="nav-number">2.2.2.</span> <span class="nav-text"> 注意</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-7"><span class="nav-number">2.2.3.</span> <span class="nav-text"> bgsave</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-8"><span class="nav-number">2.2.4.</span> <span class="nav-text"> 自动执行RDB</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-9"><span class="nav-number">2.2.5.</span> <span class="nav-text"> 自动执行RDB注意</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-10"><span class="nav-number">2.2.6.</span> <span class="nav-text"> 三种方案对比</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-11"><span class="nav-number">2.2.7.</span> <span class="nav-text"> RDB特殊启动形式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-12"><span class="nav-number">2.2.8.</span> <span class="nav-text"> RDB优点</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-13"><span class="nav-number">2.2.9.</span> <span class="nav-text"> RDB缺点</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-14"><span class="nav-number">2.3.</span> <span class="nav-text"> AOF</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#-15"><span class="nav-number">2.3.1.</span> <span class="nav-text"> RDB存储的弊端</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-16"><span class="nav-number">2.3.2.</span> <span class="nav-text"> 解决思路</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-17"><span class="nav-number">2.3.3.</span> <span class="nav-text"> 概念</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-18"><span class="nav-number">2.3.4.</span> <span class="nav-text"> AOF写数据三种策略(appendfsync)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-19"><span class="nav-number">2.3.5.</span> <span class="nav-text"> AOF配置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-20"><span class="nav-number">2.3.6.</span> <span class="nav-text"> AOF重写</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#-21"><span class="nav-number">2.3.6.1.</span> <span class="nav-text"> AOF重写作用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-22"><span class="nav-number">2.3.6.2.</span> <span class="nav-text"> AOF重写规则</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-23"><span class="nav-number">2.3.6.3.</span> <span class="nav-text"> AOF重写方式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-24"><span class="nav-number">2.3.6.4.</span> <span class="nav-text"> AOF自动重写方式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-25"><span class="nav-number">2.3.6.5.</span> <span class="nav-text"> AOF非重写流程</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-26"><span class="nav-number">2.3.6.6.</span> <span class="nav-text"> AOF重写流程</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-27"><span class="nav-number">2.4.</span> <span class="nav-text"> RDB与AOF区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-28"><span class="nav-number">2.5.</span> <span class="nav-text"> RDB与AOF怎么选</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#-29"><span class="nav-number">3.</span> <span class="nav-text"> 事务</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#-30"><span class="nav-number">3.1.</span> <span class="nav-text"> 简介</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-31"><span class="nav-number">3.2.</span> <span class="nav-text"> 基本操作</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-32"><span class="nav-number">3.3.</span> <span class="nav-text"> 事务的工作流程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-33"><span class="nav-number">3.4.</span> <span class="nav-text"> 事务的注意事项</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-34"><span class="nav-number">3.5.</span> <span class="nav-text"> 锁 – 基于特定条件的事务执行</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#-35"><span class="nav-number">3.5.1.</span> <span class="nav-text"> 乐观锁</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#-36"><span class="nav-number">3.5.1.1.</span> <span class="nav-text"> 业务分析</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-37"><span class="nav-number">3.5.1.2.</span> <span class="nav-text"> 解决方案</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-38"><span class="nav-number">3.5.2.</span> <span class="nav-text"> 分布式锁</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#-39"><span class="nav-number">3.5.2.1.</span> <span class="nav-text"> 业务分析</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-40"><span class="nav-number">3.5.2.2.</span> <span class="nav-text"> 解决方案</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-41"><span class="nav-number">3.5.3.</span> <span class="nav-text"> 死锁</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#-42"><span class="nav-number">3.5.3.1.</span> <span class="nav-text"> 业务分析</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#-43"><span class="nav-number">3.5.3.2.</span> <span class="nav-text"> 解决方案</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#-44"><span class="nav-number">4.</span> <span class="nav-text"> 删除策略</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#-45"><span class="nav-number">4.1.</span> <span class="nav-text"> Redis中的数据特征</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-46"><span class="nav-number">4.2.</span> <span class="nav-text"> 定时删除</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-47"><span class="nav-number">4.3.</span> <span class="nav-text"> 惰性删除</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-48"><span class="nav-number">4.4.</span> <span class="nav-text"> 定期删除</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-49"><span class="nav-number">4.5.</span> <span class="nav-text"> 删除策略比对</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-50"><span class="nav-number">4.6.</span> <span class="nav-text"> 逐出算法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#-51"><span class="nav-number">4.6.1.</span> <span class="nav-text"> 新数据进入检测</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-52"><span class="nav-number">4.6.2.</span> <span class="nav-text"> 影响数据逐出的相关设置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#-53"><span class="nav-number">4.6.3.</span> <span class="nav-text"> 数据逐出策略配置依据</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#-54"><span class="nav-number">5.</span> <span class="nav-text"> Redis.Conf</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#-55"><span class="nav-number">5.1.</span> <span class="nav-text"> 服务器基础配置</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-56"><span class="nav-number">5.2.</span> <span class="nav-text"> 日志配置</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-57"><span class="nav-number">5.3.</span> <span class="nav-text"> 客户端配置</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-58"><span class="nav-number">5.4.</span> <span class="nav-text"> 多服务器快捷配置</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#-59"><span class="nav-number">6.</span> <span class="nav-text"> 高级数据类型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#-60"><span class="nav-number">6.1.</span> <span class="nav-text"> Bitmaps</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-61"><span class="nav-number">6.2.</span> <span class="nav-text"> HyperLogLog</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#-62"><span class="nav-number">6.2.1.</span> <span class="nav-text"> 说明</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#-63"><span class="nav-number">6.3.</span> <span class="nav-text"> GEO</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#-64"><span class="nav-number">6.3.1.</span> <span class="nav-text"> 基本操作</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Fantasy-ke"
      src="/uploads/avatar.png">
  <p class="site-author-name" itemprop="name">Fantasy-ke</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">36</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">6</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">32</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2ZhbnRhc3kta2U=" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;fantasy-ke"><i class="fab fa-github fa-fw"></i>GitHub</span>
      </span>
      <span class="links-of-author-item">
        <span class="exturl" data-url="aHR0cHM6Ly94LmNvbS9BX0RyZWFtZXJfSGFyZA==" title="Twitter → https:&#x2F;&#x2F;x.com&#x2F;A_Dreamer_Hard"><i class="fab fa-twitter fa-fw"></i>Twitter</span>
      </span>
      <span class="links-of-author-item">
        <span class="exturl" data-url="aHR0cHM6Ly93d3cueW91dHViZS5jb20vQCVFNSU5MSVBOCVFNiVBMiVBNi16OWk=" title="YouTube → https:&#x2F;&#x2F;www.youtube.com&#x2F;@%E5%91%A8%E6%A2%A6-z9i"><i class="fab fa-youtube fa-fw"></i>YouTube</span>
      </span>
  </div>
<div class="cc-license animated" itemprop="sponsor">
  <a href="https://www.netlify.com" class="cc-opacity" title="Deploy with Netlify → https://www.netlify.com" target="_blank"><img width="80" src="https://www.netlify.com/img/global/badges/netlify-dark.svg" alt="Netlify"></a>
</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.css">
<div id="aplayer" style="position:relative;left;0;bottom:0;"></div>
<script src="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/color-thief-don@2.0.2/src/color-thief.js"></script>
<script>
  const ap = new APlayer({
    container: document.getElementById('aplayer'),
    autoplay: false, //自动播放
    listFolded: true, //播放列表默认折叠
    listMaxHeight: 90, //播放列表最大高度
    order: 'list', //音频循环顺序, 可选值: 'list', 'random'
    loop: 'all', //音频循环播放, 可选值: 'all', 'one', 'none'
    theme: '#e9e9e9', //切换音频时的主题色，优先级低于audio.theme
    preload: 'none', //音频预加载，可选值: 'none', 'metadata', 'auto'
    mutex: true, //互斥，阻止多个播放器同时播放，当前播放器播放时暂停其他播放器
    lrcType: 3, //歌词格式，可选值：3（LRC文件歌词格式），1（JS字符串歌词格式）
    volume: 0.7, //默认音量，请注意播放器会记忆用户设置，用户手动设置音量后默认音量即失效
    fixed: false, //吸底模式（fixed:true），迷你模式（mini:true），普通模式（注释此行或者设置fixed:false）
    audio: [{
        name: '平凡之路',
        artist: '朴树',
        lrc: '/downloads/lrc/平凡之路-朴树.lrc',
        cover: 'http://p2.music.126.net/W_5XiCv3rGS1-J7EXpHSCQ==/18885211718782327.jpg?param=300x300',
        url: 'http://ws.stream.qqmusic.qq.com/C4000007nRJ74eQsF6.m4a?guid=942726817&vkey=64755357C5716983BEECE2981FEC3954F0DD03E7630EFF769D9C40C31F50D53E7D260CB63E22CE8F954B1144083716A1BABFC2093F8F1C14&uin=&fromtag=120032'
      },
      {
        name: '后会无期',
        artist: '徐良,汪苏泷',
        lrc: '/downloads/lrc/后会无期-G.E.M.邓紫棋.lrc',
        cover: 'http://p1.music.126.net/vpvPajo3kn88nHc7jUjeWQ==/5974746185758035.jpg?param=300x300',
        url: 'http://ws.stream.qqmusic.qq.com/C400004ECnYg0QNchK.m4a?guid=893251117&vkey=D9DCBB8C4A4CAF8550E97A2A574DE1231DFDD8BC0989CC724742C7B9831C4108E0A805A46E0F2B2A556228467C146B9C312E3E8B498614C7&uin=&fromtag=120032'
      }
    ]
  });

  // 实现切换音频时，根据音频的封面图片自适应主题色
  const colorThief = new ColorThief();
  const setTheme = (index) => {
    if (!ap.list.audios[index].theme) {
      colorThief.getColorAsync(ap.list.audios[index].cover, function(color) {
        ap.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index);
      });
    }
  };
  setTheme(ap.list.index);
  ap.on('listswitch', (data) => {
    setTheme(data.index);
  });
</script>



        </div>
      </div>
    </div>

    
    <div class="sidebar-inner sidebar-blogroll">
      <div class="links-of-blogroll animated">
        <div class="links-of-blogroll-title"><i class="fa fa-globe fa-fw"></i>
          Links
        </div>
        <ul class="links-of-blogroll-list">
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9mYW50YXN5LWtlLmdpdGh1Yi5pbw==" title="https:&#x2F;&#x2F;fantasy-ke.github.io">SunBlog</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9mYW50YXN5LWtlLmdpdGh1Yi5pbw==" title="https:&#x2F;&#x2F;fantasy-ke.github.io">做梦的努力者</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL0ZhbnRhc3ktS2U=" title="https:&#x2F;&#x2F;github.com&#x2F;Fantasy-Ke">github</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9naXRlZS5jb20vZmFudGFzeV9rZQ==" title="https:&#x2F;&#x2F;gitee.com&#x2F;fantasy_ke">gitee</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vZmFudGFzeS1rZQ==" title="https:&#x2F;&#x2F;www.cnblogs.com&#x2F;fantasy-ke">我的园子</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9hYnAuaW8v" title="https:&#x2F;&#x2F;abp.io&#x2F;">abp</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9hYnAuaW8vZG9jcy9sYXRlc3Qv" title="https:&#x2F;&#x2F;abp.io&#x2F;docs&#x2F;latest&#x2F;">abp doc</span>
            </li>
            <li class="links-of-blogroll-item">
              <span class="exturl" data-url="aHR0cHM6Ly9ibG9ncy5tYXNhc3RhY2suY29tLw==" title="https:&#x2F;&#x2F;blogs.masastack.com&#x2F;">masa blog</span>
            </li>
        </ul>
      </div>
    </div>
        <div class="pjax">
        </div>
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="en">
    <link itemprop="mainEntityOfPage" href="https://blog.fantasyke.cn/posts/1297/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/uploads/avatar.png">
      <meta itemprop="name" content="Fantasy-ke">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Fantasy'Ke Blog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="Redis进阶 | Fantasy'Ke Blog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Redis进阶
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">Posted on</span>

      <time title="Created: 2023-05-30 12:08:00" itemprop="dateCreated datePublished" datetime="2023-05-30T12:08:00+08:00">2023-05-30</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">Edited on</span>
      <time title="Modified: 2024-12-17 14:36:35" itemprop="dateModified" datetime="2024-12-17T14:36:35+08:00">2024-12-17</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">In</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%9D%82%E4%B8%83%E6%9D%82%E5%85%AB%E7%9A%84%E7%A0%96/" itemprop="url" rel="index"><span itemprop="name">杂七杂八的砖</span></a>
        </span>
    </span>

  
    <span class="post-meta-item" title="Views" id="busuanzi_container_page_pv">
      <span class="post-meta-item-icon">
        <i class="far fa-eye"></i>
      </span>
      <span class="post-meta-item-text">Views: </span>
      <span id="busuanzi_value_page_pv"></span>
    </span>
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="Word count in article">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">Word count in article: </span>
      <span>5.9k</span>
    </span>
    <span class="post-meta-item" title="Reading time">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">Reading time &asymp;</span>
      <span>22 mins.</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><!-- more -->
<!-- - [.NET Core操作Redis](#net-core操作redis)
- [持久化](#持久化)
  - [持久化过程保存什么](#持久化过程保存什么)
  - [RDB](#rdb)
    - [RDB持久化的配置](#rdb持久化的配置)
    - [自动执行RDB](#自动执行rdb)
    - [自动执行RDB注意](#自动执行rdb注意)
    - [三种方案对比](#三种方案对比)
    - [RDB特殊启动形式](#rdb特殊启动形式)
    - [RDB优点](#rdb优点)
    - [RDB缺点](#rdb缺点)
  - [AOF](#aof)
    - [RDB存储的弊端](#rdb存储的弊端)
    - [概念](#概念)
    - [AOF写数据三种策略(appendfsync)](#aof写数据三种策略appendfsync)
    - [AOF配置](#aof配置)
    - [AOF重写](#aof重写)
      - [AOF重写作用](#aof重写作用)
      - [AOF重写规则](#aof重写规则)
      - [AOF重写方式](#aof重写方式)
      - [AOF自动重写方式](#aof自动重写方式)
      - [AOF重写流程](#aof重写流程)
  - [RDB与AOF区别](#rdb与aof区别)
  - [RDB与AOF怎么选](#rdb与aof怎么选)
- [事务](#事务)
  - [简介](#简介)
  - [基本操作](#基本操作)
  - [事务的工作流程](#事务的工作流程)
  - [事务的注意事项](#事务的注意事项)
  - [锁 – 基于特定条件的事务执行](#锁--基于特定条件的事务执行)
    - [乐观锁](#乐观锁)
      - [业务分析](#业务分析)
    - [分布式锁](#分布式锁)
      - [业务分析](#业务分析-1)
    - [死锁](#死锁)
      - [业务分析](#业务分析-2)
- [删除策略](#删除策略)
  - [Redis中的数据特征](#redis中的数据特征)
  - [定时删除](#定时删除)
  - [惰性删除](#惰性删除)
  - [定期删除](#定期删除)
  - [删除策略比对](#删除策略比对)
  - [逐出算法](#逐出算法)
    - [新数据进入检测](#新数据进入检测)
- [Redis.Conf](#redisconf)
  - [服务器基础配置](#服务器基础配置)
  - [日志配置](#日志配置)
  - [客户端配置](#客户端配置)
- [高级数据类型](#高级数据类型)
  - [Bitmaps](#bitmaps)
  - [HyperLogLog](#hyperloglog)
    - [说明](#说明)
  - [GEO](#geo) -->
<h1 id=""><a class="markdownIt-Anchor" href="#"></a> <a href="#NET-Core%E6%93%8D%E4%BD%9CRedis" title=".NET Core操作Redis"></a>.NET Core操作Redis</h1>
<p>创建控制台应用<code>RedisSample01</code>，通过<code>nuget</code>引入<code>CSRedisCore</code></p>
<p>具体示例代码如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">using System;  </span><br><span class="line">using System.Linq;  </span><br><span class="line">using System.Threading.Tasks;  </span><br><span class="line">using CSRedis;  </span><br><span class="line">  </span><br><span class="line">namespace RedisSample01  </span><br><span class="line">&#123;  </span><br><span class="line">    class Program  </span><br><span class="line">    &#123;  </span><br><span class="line">        static async Task Main(string\[\] args)  </span><br><span class="line">        &#123;  </span><br><span class="line">        </span><br><span class="line">        var redis = new CSRedisClient(<span class="string">&quot;127.0.0.1:6379,defaultDatabase=0,prefix=ds_&quot;</span>);  </span><br><span class="line">        RedisHelper.Initialization(redis);  </span><br><span class="line">        </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;↓↓↓↓↓ String Sample ↓↓↓↓↓&quot;</span>);  </span><br><span class="line">        await RedisHelper.SetAsync(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;dimsum&quot;</span>);  </span><br><span class="line">        var name = await RedisHelper.GetAsync&lt;string&gt;(<span class="string">&quot;name&quot;</span>);  </span><br><span class="line">        Console.WriteLine($<span class="string">&quot;name = &#123;name&#125;&quot;</span>);  </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;↑↑↑↑↑ Sample End ↑↑↑↑↑↑&quot;</span>);  </span><br><span class="line">        Console.WriteLine();  </span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;↓↓↓↓↓ List Sample ↓↓↓↓↓&quot;</span>);  </span><br><span class="line">        await RedisHelper.DelAsync(<span class="string">&quot;list1&quot;</span>);  </span><br><span class="line">        await RedisHelper.LPushAsync(<span class="string">&quot;list1&quot;</span>, <span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>);  </span><br><span class="line">        await RedisHelper.RPushAsync(<span class="string">&quot;list1&quot;</span>, <span class="string">&quot;x&quot;</span>);  </span><br><span class="line">        </span><br><span class="line">        var list1 =await RedisHelper.LRangeAsync(<span class="string">&quot;list1&quot;</span>, 0, -1);  </span><br><span class="line">        Console.WriteLine($<span class="string">&quot;list1 = &#123;String.Join(&#x27;,&#x27;,list1)&#125;&quot;</span>);  </span><br><span class="line">        var list1Length = await redis.LLenAsync(<span class="string">&quot;list1&quot;</span>);  </span><br><span class="line">        Console.WriteLine($<span class="string">&quot;list1.length = &#123;list1Length&#125;&quot;</span>);  </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;↑↑↑↑↑ Sample End ↑↑↑↑↑↑&quot;</span>);  </span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;↓↓↓↓↓ Hash Sample ↓↓↓↓↓&quot;</span>);  </span><br><span class="line">        </span><br><span class="line">        await RedisHelper.HSetAsync(<span class="string">&quot;hash1&quot;</span>, <span class="string">&quot;name&quot;</span>, <span class="string">&quot;张三&quot;</span>);  </span><br><span class="line">        await RedisHelper.HSetAsync(<span class="string">&quot;hash1&quot;</span>, <span class="string">&quot;age&quot;</span>, 19);  </span><br><span class="line">        await RedisHelper.HSetAsync(<span class="string">&quot;hash1&quot;</span>, <span class="string">&quot;job&quot;</span>, <span class="string">&quot;C#&quot;</span>);  </span><br><span class="line">        </span><br><span class="line">        var hash1 = await RedisHelper.HGetAllAsync(<span class="string">&quot;hash1&quot;</span>);  </span><br><span class="line">        Console.WriteLine($<span class="string">&quot;hash1 = &#123;string.Join(&#x27;,&#x27;, hash1.Select(x =&gt; $&quot;</span>&#123;x.Key&#125;:&#123;x.Value&#125;<span class="string">&quot;).ToArray())&#125;&quot;</span>);  </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;↑↑↑↑↑ Sample End ↑↑↑↑↑↑&quot;</span>);  </span><br><span class="line">        </span><br><span class="line">        Console.WriteLine();  </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;====================&quot;</span>);  </span><br><span class="line">        Console.WriteLine(<span class="string">&quot;Sample done&quot;</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;  </span><br></pre></td></tr></table></figure>
<h1 id="-2"><a class="markdownIt-Anchor" href="#-2"></a> <a href="#%E6%8C%81%E4%B9%85%E5%8C%96" title="持久化"></a>持久化</h1>
<ul>
<li>持久化：利用永久性存储介质将数据进行保存，在特定的时间将保存的数据进行恢复的工作机制</li>
<li>为什么要持久化？防止数据的意外丢失，确保数据安全</li>
</ul>
<h2 id="-3"><a class="markdownIt-Anchor" href="#-3"></a> <a href="#%E6%8C%81%E4%B9%85%E5%8C%96%E8%BF%87%E7%A8%8B%E4%BF%9D%E5%AD%98%E4%BB%80%E4%B9%88" title="持久化过程保存什么"></a>持久化过程保存什么</h2>
<ul>
<li>RDB：将当前数据状态进行保存，快照形式，存储数据结果，存储格式简单，关注点在数据</li>
<li>AOF：将数据的操作过程进行保存，日志形式，存储操作过程，存储格式复杂，关注点在数据的操作过程</li>
</ul>
<h2 id="-4"><a class="markdownIt-Anchor" href="#-4"></a> <a href="#RDB" title="RDB"></a>RDB</h2>
<ul>
<li>操作命令：<code>save</code></li>
<li>作用：手动执行一次保存操作</li>
</ul>
<h3 id="-5"><a class="markdownIt-Anchor" href="#-5"></a> <a href="#RDB%E6%8C%81%E4%B9%85%E5%8C%96%E7%9A%84%E9%85%8D%E7%BD%AE" title="RDB持久化的配置"></a>RDB持久化的配置</h3>
<p><strong>在配置文件中修改</strong></p>
<ul>
<li>
<p>dbfilename dump.rdb</p>
<ul>
<li>说明：设置本地数据库文件名，默认为<code>dump.rdb</code></li>
<li>经验：通常设置为<code>dump-端口号.rdb</code></li>
</ul>
</li>
<li>
<p>dir</p>
<ul>
<li>说明：设置存储<code>.rdb</code>文件的路径</li>
<li>经验：通常设置成存储空间较大的目录中，目录名称<code>data</code></li>
</ul>
</li>
<li>
<p>rdbcompression yes</p>
<ul>
<li>说明：设置存储至本地数据库时是否压缩数据，默认为<code>yes</code>，采用<code>LZF</code>压缩</li>
<li>经验：通常默认为开启状态，如果设置为<code>no</code>，可以节省CPU运行时间，但会使存储的文件变大(巨大)</li>
</ul>
</li>
<li>
<p>rdbchecksum yes</p>
<ul>
<li>说明：设置是否进行<code>RDB</code>文件格式校验，该校验过程在写文件和读文件过程均进行</li>
<li>经验：通常默认为开启状态，如果设置为no，可以节约读写行过程约10%时间消耗，但是存储一定的数据损坏风险</li>
</ul>
</li>
<li>
<p>stop-writes-on-bgsave-error yes</p>
<ul>
<li>
<p>说明：后台存储过程中如果出现错误现象，是否停止保存操作(这个配置项针对bgsave操作)</p>
</li>
<li>
<p>经验：通常默认为开启状态</p>
<h3 id="-6"><a class="markdownIt-Anchor" href="#-6"></a> <a href="#%E6%B3%A8%E6%84%8F" title="注意"></a>注意</h3>
</li>
</ul>
</li>
<li>
<p><em>save指令的执行会阻塞当前Redis服务器，知道当前RDB过程完成位置，有可能会造成长时间阻塞，线上环境不建议使用*</em></p>
<h3 id="-7"><a class="markdownIt-Anchor" href="#-7"></a> <a href="#bgsave" title="bgsave"></a>bgsave</h3>
</li>
<li>
<p>操作命令：<code>bgsave</code></p>
</li>
<li>
<p>作用：手动启动后台保存操作，但不是立即执行</p>
</li>
</ul>
<p><strong>注意：bgsave命令是针对save阻塞问题做的优化，redis内部所有涉及到RDB操作都采用bgsave的方式，save命令可以放弃使用</strong><br />
<img src="https://fantasy-ke.github.io/picx-images-hosting/redis/image.3nrn361nc4.webp" alt="bgsave.png" /></p>
<h3 id="-8"><a class="markdownIt-Anchor" href="#-8"></a> <a href="#%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8CRDB" title="自动执行RDB"></a>自动执行RDB</h3>
<ul>
<li>配置：<code>save second changes</code></li>
<li>作用：满足限定时间范围内key的变化数量达到指定数量，即进行持久化</li>
<li>参数：
<ul>
<li>second：监控时间范围</li>
<li>changes：监控<code>key</code>的变化量</li>
</ul>
</li>
<li>位置：在conf文件中进行配置</li>
<li>示例：
<ul>
<li><code>save 900 1</code> -&gt; 900秒内变化1个即触发RDB</li>
<li><code>save 300 10</code> -&gt; 300秒内变化10个即触发RDB</li>
<li><code>save 60 10000</code> -&gt; 60秒内变化10000个即触发RDB</li>
</ul>
</li>
<li>经验：一般监控时间大，变化时间小</li>
</ul>
<h3 id="-9"><a class="markdownIt-Anchor" href="#-9"></a> <a href="#%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8CRDB%E6%B3%A8%E6%84%8F" title="自动执行RDB注意"></a>自动执行RDB注意</h3>
<ul>
<li><code>save</code>配置要根据实际业务情况进行设置，频度过高或过低都会出现性能问题，结果可能是灾难性的</li>
<li><code>save</code>配置中对于<code>second</code>与<code>changes</code>设置通常具有互补对应关系，尽量不要设置成包含行关系</li>
<li><code>save</code>配置启动后执行的是<code>bgsave</code>操作</li>
</ul>
<h3 id="-10"><a class="markdownIt-Anchor" href="#-10"></a> <a href="#%E4%B8%89%E7%A7%8D%E6%96%B9%E6%A1%88%E5%AF%B9%E6%AF%94" title="三种方案对比"></a>三种方案对比</h3>
<table>
<thead>
<tr>
<th>方式</th>
<th>save指令</th>
<th>bgsave指令</th>
<th>save配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>读写</td>
<td>同步</td>
<td>异步</td>
<td>阻塞客户端指令</td>
</tr>
<tr>
<td>是</td>
<td>否</td>
<td>额外内存消耗</td>
<td>否</td>
</tr>
<tr>
<td>是</td>
<td>启动新进程</td>
<td>否</td>
<td>是</td>
</tr>
</tbody>
</table>
<h3 id="-11"><a class="markdownIt-Anchor" href="#-11"></a> <a href="#RDB%E7%89%B9%E6%AE%8A%E5%90%AF%E5%8A%A8%E5%BD%A2%E5%BC%8F" title="RDB特殊启动形式"></a>RDB特殊启动形式</h3>
<ul>
<li>全量复制：（主从复制再说）</li>
<li>服务器运行过程中重启：<code>debug reload</code></li>
<li>关闭服务器时指定保存数据：<code>shutdown save</code></li>
</ul>
<h3 id="-12"><a class="markdownIt-Anchor" href="#-12"></a> <a href="#RDB%E4%BC%98%E7%82%B9" title="RDB优点"></a>RDB优点</h3>
<ul>
<li><code>RDB</code>是一个紧凑压缩的二进制文件，存储效率较高</li>
<li><code>RDB</code>内部存储的是redis在某个时间点的数据快照，非常适合用于数据备份，全量复制等场景</li>
<li><code>RDB</code>恢复数据的速度要比<code>AOF</code>快很多</li>
<li>应用：服务器中每N小时执行<code>bgsave</code>备份，并将<code>RDB</code>文件拷贝到远程服务器中，用于灾难恢复</li>
</ul>
<h3 id="-13"><a class="markdownIt-Anchor" href="#-13"></a> <a href="#RDB%E7%BC%BA%E7%82%B9" title="RDB缺点"></a>RDB缺点</h3>
<ul>
<li><code>RDB</code>方式无论是执行指令还是利用配置，无法做到实时持久化，具有较大的可能性丢失数据</li>
<li><code>bgsave</code>指令每次运行要执行<code>fork</code>操作创建子进程，要牺牲掉一些性能</li>
<li><code>Redis</code>的众多版本中未进行<code>RDB</code>文件格式的版本统一，有可能出现各版本服务之间数据格式无法兼容现象</li>
</ul>
<h2 id="-14"><a class="markdownIt-Anchor" href="#-14"></a> <a href="#AOF" title="AOF"></a>AOF</h2>
<h3 id="-15"><a class="markdownIt-Anchor" href="#-15"></a> <a href="#RDB%E5%AD%98%E5%82%A8%E7%9A%84%E5%BC%8A%E7%AB%AF" title="RDB存储的弊端"></a>RDB存储的弊端</h3>
<ul>
<li>
<p>存储数据量较大，效率较低。基于快照思想，每次读写都是全部数据，当数据量巨大时，效率非常低</p>
</li>
<li>
<p>大数据量下的IO性能较低</p>
</li>
<li>
<p>基于<code>fork</code>创建子进程，内存产生额外消耗</p>
</li>
<li>
<p>宕机带来的数据丢失风险</p>
<h3 id="-16"><a class="markdownIt-Anchor" href="#-16"></a> <a href="#%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF" title="解决思路"></a>解决思路</h3>
</li>
<li>
<p>不写全数据，仅记录部分数据</p>
</li>
<li>
<p>改记录数据为记录操作过程</p>
</li>
<li>
<p>对所有数据操作均进行记录，排除丢失数据的风险</p>
</li>
</ul>
<h3 id="-17"><a class="markdownIt-Anchor" href="#-17"></a> <a href="#%E6%A6%82%E5%BF%B5" title="概念"></a>概念</h3>
<ul>
<li>AOP(append only file)持久化：以独立日志的方式记录每次写命令，重启时再重新执行<code>AOF</code>文件中命令，以达到恢复数据的目的，与<code>RDB</code>相比可以简单描述为<strong>改记录数据为记录数据产生的过程</strong></li>
<li><code>AOF</code>的主要作用是解决了数据持久化的实时性，目前已经是<code>Redis</code>持久化的主流方式</li>
</ul>
<p><img src="https://fantasy-ke.github.io/picx-images-hosting/redis/image.491apgw8io.webp" alt="image.png" /></p>
<h3 id="-18"><a class="markdownIt-Anchor" href="#-18"></a> <a href="#AOF%E5%86%99%E6%95%B0%E6%8D%AE%E4%B8%89%E7%A7%8D%E7%AD%96%E7%95%A5-appendfsync" title="AOF写数据三种策略(appendfsync)"></a>AOF写数据三种策略(appendfsync)</h3>
<ul>
<li>always(每次)：每次写入操作均同步到<code>AOF</code>文件中，数据零误差，性能较差</li>
<li>everysec(每秒)：每秒将缓冲区的指令同步到<code>AOF</code>文件中，数据准确性较高，性能较高，在系统突然宕机的情况下丢失1秒内的数据。<strong>建议使用，也是默认配置项</strong></li>
<li>no(系统控制)：由操作系统控制每次同步到<code>AOF</code>文件的周期，整体过程不可控</li>
</ul>
<h3 id="-19"><a class="markdownIt-Anchor" href="#-19"></a> <a href="#AOF%E9%85%8D%E7%BD%AE" title="AOF配置"></a>AOF配置</h3>
<ul>
<li>配置：<code>appendonly yes|no</code>
<ul>
<li>作用：是否开启<code>AOF</code>持久化功能，默认为不开启状态</li>
<li>经验：开启</li>
</ul>
</li>
<li>配置：<code>appendfsync always|everysec|no</code>
<ul>
<li>作用：<code>AOF</code>写数据策略</li>
<li>经验：<code>everysec</code></li>
</ul>
</li>
<li>配置：<code>appendfilename filename</code>
<ul>
<li>作用：<code>AOF</code>持久化文件名，默认文件名为<code>appendonly.aof</code></li>
<li>经验：建议配置为<code>appendonly-端口号.aof</code></li>
</ul>
</li>
<li>配置：<code>dir</code>
<ul>
<li>作用：<code>AOF</code>持久化文件保存路径</li>
<li>经验：与<code>RDB</code>持久化文件保持一致即可</li>
</ul>
</li>
</ul>
<h3 id="-20"><a class="markdownIt-Anchor" href="#-20"></a> <a href="#AOF%E9%87%8D%E5%86%99" title="AOF重写"></a>AOF重写</h3>
<p>随着命令不断写入<code>AOF</code>，文件会越来越大，为了解决这个问题，Redis引入了<code>AOF</code>重写机制压缩文件体积。<code>AOF</code>文件重写是将Redis进程内的数据转化为些命令同步到新<code>AOF</code>文件的过程。简单说就是将对同一个数据的若干条命令执行结果转化成最终结果数据对应的指令进行记录。</p>
<h4 id="-21"><a class="markdownIt-Anchor" href="#-21"></a> <a href="#AOF%E9%87%8D%E5%86%99%E4%BD%9C%E7%94%A8" title="AOF重写作用"></a>AOF重写作用</h4>
<ul>
<li>降低磁盘占用量，提高磁盘利用率</li>
<li>提高持久化效率，降低持久化写时间，提升IO性能</li>
<li>降低数据恢复用时，提高数据恢复效率</li>
</ul>
<h4 id="-22"><a class="markdownIt-Anchor" href="#-22"></a> <a href="#AOF%E9%87%8D%E5%86%99%E8%A7%84%E5%88%99" title="AOF重写规则"></a>AOF重写规则</h4>
<ul>
<li>进程内已超时的数据不再写入文件</li>
<li>忽略无效指令，重写时使用进程内数据直接生成，这样新的AOF文件只保留最终数据的写入命令
<ul>
<li>如：<code>del key1、hdel key2、srem key3、set key4 111、set key4 222</code></li>
</ul>
</li>
<li>对同一数据的多条写命令合并为同一条命令
<ul>
<li>如：<code>push list1 a、lpush list1 b、lpush list1 c</code>可以转为：<code>lpush list1 a b c</code></li>
<li>为了防止数据量过大造成客户端缓冲区溢出，对<code>list</code>、<code>set</code>、<code>hash</code>、<code>zset</code>等类型，每条指令最多写入64个元素</li>
</ul>
</li>
</ul>
<h4 id="-23"><a class="markdownIt-Anchor" href="#-23"></a> <a href="#AOF%E9%87%8D%E5%86%99%E6%96%B9%E5%BC%8F" title="AOF重写方式"></a>AOF重写方式</h4>
<ul>
<li>
<p>手动重写：<code>bgrewriteaof</code></p>
</li>
<li>
<p>自动重写</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">auto-aof-rewrite-min-size size  </span><br><span class="line">auto-aof-rewrite-percentage percentage  </span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="-24"><a class="markdownIt-Anchor" href="#-24"></a> <a href="#AOF%E8%87%AA%E5%8A%A8%E9%87%8D%E5%86%99%E6%96%B9%E5%BC%8F" title="AOF自动重写方式"></a>AOF自动重写方式</h4>
<ul>
<li>
<p>自动重写触发条件设置</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">auto-aof-rewrite-min-size size --自动AOF的重写尺寸(默认值比较大)  </span><br><span class="line">auto-aof-rewrite-percentage percent  --自动重写的百分比  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>自动重写触发对比参数（运行指令info persistence获取具体信息）</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">aof_current_size  </span><br><span class="line">aof_base_size  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>自动重写触发条件</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">aof_current_size &gt; auto_aof_rewrite_min_size  </span><br><span class="line">aof_current_size - aof_base_size / aof_base_size &gt;= auto-aof-rewrite-percentage  </span><br></pre></td></tr></table></figure>
<h4 id="-25"><a class="markdownIt-Anchor" href="#-25"></a> <a href="#AOF%E9%9D%9E%E9%87%8D%E5%86%99%E6%B5%81%E7%A8%8B" title="AOF非重写流程"></a>AOF非重写流程</h4>
<p><img src="https://fantasy-ke.github.io/picx-images-hosting/redis/image.esj6iefr9.webp" alt="image.png" /></p>
</li>
</ul>
<h4 id="-26"><a class="markdownIt-Anchor" href="#-26"></a> <a href="#AOF%E9%87%8D%E5%86%99%E6%B5%81%E7%A8%8B" title="AOF重写流程"></a>AOF重写流程</h4>
<p><img src="https://fantasy-ke.github.io/picx-images-hosting/redis/image.45horr3f9n.webp" alt="image.png" /></p>
<h2 id="-27"><a class="markdownIt-Anchor" href="#-27"></a> <a href="#RDB%E4%B8%8EAOF%E5%8C%BA%E5%88%AB" title="RDB与AOF区别"></a>RDB与AOF区别</h2>
<table>
<thead>
<tr>
<th>持久方式</th>
<th>RDB</th>
<th>AOF</th>
</tr>
</thead>
<tbody>
<tr>
<td>占用存储空间</td>
<td>小（数据级：压缩）</td>
<td>大（指令集：重写）</td>
</tr>
<tr>
<td>存储速度</td>
<td>慢</td>
<td>快</td>
</tr>
<tr>
<td>恢复速度</td>
<td>快</td>
<td>慢</td>
</tr>
<tr>
<td>数据安全性</td>
<td>会丢失数据</td>
<td>依据策略决定</td>
</tr>
<tr>
<td>消耗资源</td>
<td>高/重量级</td>
<td>低/轻量级</td>
</tr>
<tr>
<td>启动优先级</td>
<td>低</td>
<td>高</td>
</tr>
</tbody>
</table>
<h2 id="-28"><a class="markdownIt-Anchor" href="#-28"></a> <a href="#RDB%E4%B8%8EAOF%E6%80%8E%E4%B9%88%E9%80%89" title="RDB与AOF怎么选"></a>RDB与AOF怎么选</h2>
<ul>
<li>对数据非常敏感，建议使用默认的<code>AOF</code>持久化方案
<ul>
<li><code>AOF</code>持久化策略使用<code>everysecond</code>，每秒钟<code>fsync</code>一次。该策略redis仍然可以保持很好的性能，当出现问题时，最多丢失0-1秒钟的数据</li>
<li>注意：<code>AOF</code>文件存储体积较大，且恢复速度较慢</li>
</ul>
</li>
<li>数据呈现具有有效性，建议使用<code>RDB</code>持久化方案
<ul>
<li>数据可以良好的做到阶段内无丢失（该阶段是开发者或运维人员手工维护的），且恢复速度快，阶段点数据恢复通常采用<code>RDB</code>方案</li>
<li>注意：利用<code>RDB</code>实现紧凑的数据持久化会使Redis性能降得很低</li>
</ul>
</li>
<li>综合比对
<ul>
<li><code>RDB</code>与<code>AOF</code>的选择实际上是在做一种权衡，每种都有利弊</li>
<li>如不能承受数分钟以内的数据丢失，对业务数据非常敏感，选用<code>AOF</code></li>
<li>如能承受数分钟以内的数据丢失，且追求大数据的恢复速度，选用<code>RDB</code></li>
<li>灾难恢复选用<code>AOF</code></li>
<li>双保险策略，同时开启<code>RDB</code>和<code>AOF</code>，重启后，Redis优先使用<code>AOF</code>来恢复数据，降低丢失数据的量</li>
</ul>
</li>
</ul>
<h1 id="-29"><a class="markdownIt-Anchor" href="#-29"></a> <a href="#%E4%BA%8B%E5%8A%A1" title="事务"></a>事务</h1>
<h2 id="-30"><a class="markdownIt-Anchor" href="#-30"></a> <a href="#%E7%AE%80%E4%BB%8B" title="简介"></a>简介</h2>
<p>为什么要有事务：Redis执行指令过程中，多条连续执行的指令被干扰、打断、插队</p>
<p>Redis事务就是一个命令执行的队列，将一系列预定义命令包装成一个整体（一个队列）。当执行时，一次性按照添加顺序依次执行，中间不会被打断或干扰。</p>
<p>一个队伍中，一次性、顺序性、排他性的执行一系列命令</p>
<h2 id="-31"><a class="markdownIt-Anchor" href="#-31"></a> <a href="#%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C" title="基本操作"></a>基本操作</h2>
<ul>
<li>开启事务：<code>multi</code>
<ul>
<li>作用：设定事务的开启位置，此指令执行后，后续的所有指令均加入到事务中</li>
</ul>
</li>
<li>执行事务：<code>exec</code>
<ul>
<li>作用：设定事务的结束位置，同时执行事务。与<code>multi</code>成对出现，成对使用</li>
</ul>
</li>
<li>取消事务：<code>discard</code>
<ul>
<li>作用：终止当前事务的定义，发生在<code>multi</code>之后，<code>exex</code>之前</li>
</ul>
</li>
</ul>
<p><strong>注意：加入事务的命令暂时进入到任务队列中，并没有立即执行，只有执行<code>exec</code>命令才开始执行</strong></p>
<h2 id="-32"><a class="markdownIt-Anchor" href="#-32"></a> <a href="#%E4%BA%8B%E5%8A%A1%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B" title="事务的工作流程"></a>事务的工作流程</h2>
<p><img src="https://fantasy-ke.github.io/picx-images-hosting/redis/image.1hs8heaien.webp" alt="image.png" /></p>
<h2 id="-33"><a class="markdownIt-Anchor" href="#-33"></a> <a href="#%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" title="事务的注意事项"></a>事务的注意事项</h2>
<ul>
<li>定义事务的过程中，命令格式输入错误怎么办？
<ul>
<li>语法错误：指命令书写格式有误</li>
<li>处理结果：如果定义的事务中所包含存在语法错误，整体事务中所有命令均不会执行，包括那些语法正确的命令</li>
</ul>
</li>
<li>定义事务的过程中，命令执行出现错误怎么办？
<ul>
<li>运行错误：指命令格式正确，但是无法正确的执行，例如对<code>list</code>进行<code>incr</code>操作</li>
<li>处理结果：能够正确运行的命令会执行，运行错误的命令不会执行</li>
</ul>
</li>
</ul>
<p><strong>注意：已经执行的命令对应的数据不会自动回滚，需要程序员自己在代码中实现回滚</strong></p>
<ul>
<li>手动进行事务回滚（无奈之举才用）
<ul>
<li>记录操作过程中被影响的数据之前的状态
<ul>
<li>单数据：<code>string</code></li>
<li>多数据：<code>hash</code>、<code>list</code>、<code>set</code>、<code>zset</code></li>
</ul>
</li>
<li>设置指令恢复所有的被修改的项
<ul>
<li>单数据：直接<code>set</code>（注意周边属性，例如时效）</li>
<li>多数据：修改对应值或整体克隆复制</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="-34"><a class="markdownIt-Anchor" href="#-34"></a> <a href="#%E9%94%81-%E2%80%93-%E5%9F%BA%E4%BA%8E%E7%89%B9%E5%AE%9A%E6%9D%A1%E4%BB%B6%E7%9A%84%E4%BA%8B%E5%8A%A1%E6%89%A7%E8%A1%8C" title="锁 – 基于特定条件的事务执行"></a>锁 – 基于特定条件的事务执行</h2>
<h3 id="-35"><a class="markdownIt-Anchor" href="#-35"></a> <a href="#%E4%B9%90%E8%A7%82%E9%94%81" title="乐观锁"></a>乐观锁</h3>
<h4 id="-36"><a class="markdownIt-Anchor" href="#-36"></a> <a href="#%E4%B8%9A%E5%8A%A1%E5%88%86%E6%9E%90" title="业务分析"></a>业务分析</h4>
<ul>
<li>
<p>多个客户端都有可能同时操作同一组数据，并且该数据一旦被操作修改后，将不适用于继续操作</p>
</li>
<li>
<p>在操作之前锁定要操作的数据，一旦发生变化，终止当前操作</p>
<h4 id="-37"><a class="markdownIt-Anchor" href="#-37"></a> <a href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" title="解决方案"></a>解决方案</h4>
</li>
<li>
<p>对<code>key</code>添加监视锁，在执行<code>exec</code>前如果<code>key</code>发生了变化，终止事务执行：<code>watch key1 [key2...]</code></p>
</li>
<li>
<p>取消对所有<code>key</code>的监视：<code>unwatch</code></p>
</li>
<li>
<p><code>watch</code>命令在事务开启之前，然后在执行事务的<code>exec</code>的时候，会判断<code>watch</code>的值是否已经发生变化，如果没有则正常事务执行，如果发生了变化，则操作<code>watch</code>的命令失败</p>
</li>
</ul>
<h3 id="-38"><a class="markdownIt-Anchor" href="#-38"></a> <a href="#%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81" title="分布式锁"></a>分布式锁</h3>
<h4 id="-39"><a class="markdownIt-Anchor" href="#-39"></a> <a href="#%E4%B8%9A%E5%8A%A1%E5%88%86%E6%9E%90-1" title="业务分析"></a>业务分析</h4>
<ul>
<li>
<p>使用<code>watch</code>监控一个<code>key</code>有没有改变已经不能解决问题，此处要监控的是具体数据</p>
</li>
<li>
<p>虽然Redis是单线程，但是多个客户对同一个数据同时进行操作时，如何避免不被同时修改</p>
<h4 id="-40"><a class="markdownIt-Anchor" href="#-40"></a> <a href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-1" title="解决方案"></a>解决方案</h4>
</li>
<li>
<p>设置<code>setnx</code>设置一个公共锁：<code>setnx lock-key value</code></p>
<ul>
<li>利用<code>setnx</code>命令的返回值特征，有值则返回设置失败，无值则返回设置成功</li>
<li>对于返回设置成功的，拥有控制权，进行下一步的具体业务操作</li>
<li>对于返回设置失败的，不具有控制权，排队或等待</li>
<li>操作完毕通过<code>del</code>操作释放锁</li>
</ul>
</li>
</ul>
<h3 id="-41"><a class="markdownIt-Anchor" href="#-41"></a> <a href="#%E6%AD%BB%E9%94%81" title="死锁"></a>死锁</h3>
<h4 id="-42"><a class="markdownIt-Anchor" href="#-42"></a> <a href="#%E4%B8%9A%E5%8A%A1%E5%88%86%E6%9E%90-2" title="业务分析"></a>业务分析</h4>
<ul>
<li>
<p>由于锁操作由用户控制加锁解锁，必定会存在加所有未解锁的风险</p>
</li>
<li>
<p>需要解锁操作不能仅依赖用户控制，系统级别要能给出对应的保底处理方案</p>
<h4 id="-43"><a class="markdownIt-Anchor" href="#-43"></a> <a href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-2" title="解决方案"></a>解决方案</h4>
</li>
<li>
<p>使用<code>expire</code>为锁<code>key</code>添加时间限定，到时不释放锁，放弃锁</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">expire lock-key second  </span><br><span class="line">pexpire lock-key milliseconds  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>由于操作通常都是微妙或毫秒级，因此该锁定时间不宜设置过长，具体时间需要业务测试后确定</p>
<ul>
<li>例如：持有锁的操作最长执行时间127ms，最短执行时间7ms</li>
<li>测试百万次最长执行时间对应命令的最大耗时，测试百万次网络延迟平均耗时</li>
<li>锁时间设定推荐：<code>最大耗时*120% + 平均网络延迟*100%</code></li>
<li>如果业务最大耗时&lt;&lt;网络平均耗时，通常为2个数量级，取其中单个耗时较长即可</li>
</ul>
</li>
</ul>
<h1 id="-44"><a class="markdownIt-Anchor" href="#-44"></a> <a href="#%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5" title="删除策略"></a>删除策略</h1>
<h2 id="-45"><a class="markdownIt-Anchor" href="#-45"></a> <a href="#Redis%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%89%B9%E5%BE%81" title="Redis中的数据特征"></a>Redis中的数据特征</h2>
<ul>
<li>Redis是一种内存及数据库，所有数据均存放在内存中，内存中的数据可以通过<code>TTL</code>指令获取其状态
<ul>
<li>XX：具有时效性的数据</li>
<li>-1：永久有效的数据</li>
<li>-2：已经过期的数据 或 被删除的数据 或 未定义的数据</li>
</ul>
</li>
</ul>
<p>数据删除策略的目的：在内存占用与CPU占用之间寻找一种平衡，顾此失彼都会造成整体Redis性能的下降，甚至引发服务器宕机或内存泄露</p>
<h2 id="-46"><a class="markdownIt-Anchor" href="#-46"></a> <a href="#%E5%AE%9A%E6%97%B6%E5%88%A0%E9%99%A4" title="定时删除"></a>定时删除</h2>
<p>创建一个定时器，当<code>key</code>设置由过期时间，且过期时间到达时，由定时器立即执行对键的删除操作</p>
<ul>
<li>优点：解决内存，到时就删除，快速释放掉不必要的内存占用</li>
<li>缺点：CPU压力很大，无论CPU此时负载量多高，均占用CPU，会影响Redis服务器响应时间和指令吞吐量</li>
<li>总结：用处理器性能换存储空间（拿时间换空间）</li>
</ul>
<h2 id="-47"><a class="markdownIt-Anchor" href="#-47"></a> <a href="#%E6%83%B0%E6%80%A7%E5%88%A0%E9%99%A4" title="惰性删除"></a>惰性删除</h2>
<p>数据到达过期时间，不做处理，等下次访问该数据时再进行删除，并返回不存在</p>
<ul>
<li>优点：节约CPU性能，发现必须删除的时候才删除</li>
<li>缺点：内存压力很大，出现长期占用内存的数据</li>
<li>总结：用存储空间换取处理器性能（拿空间换时间）</li>
</ul>
<h2 id="-48"><a class="markdownIt-Anchor" href="#-48"></a> <a href="#%E5%AE%9A%E6%9C%9F%E5%88%A0%E9%99%A4" title="定期删除"></a>定期删除</h2>
<ul>
<li>
<p>Redis启动服务器初始化时，读取配置server.hz的值，默认为10</p>
</li>
<li>
<p>每秒执行server.hz次<code>serverCron()-&gt;databaseCron()-&gt;activeExpireCycle()</code></p>
</li>
<li>
<p><code>activeExpireCycle()</code>对每个<code>expires[*]</code>逐一进行检测，每次执行250ms/server.hz</p>
</li>
<li>
<p>对某个<code>expires[*]</code>检测时，随机挑选W个key检测</p>
<ul>
<li>如果key超时，删除key</li>
<li>如果一轮中删除的key的数量 &gt; W*25%，则循环该过程</li>
<li>如果一轮中删除的key的数量 &lt;= W_25%，检查下一个`expires[_]`，db0-db15循环</li>
<li>W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值</li>
</ul>
</li>
<li>
<p>参数<code>current_db</code>用来记录<code>activeExpireCycle()</code>进入那个<code>expires[*]</code>执行</p>
</li>
<li>
<p>周期性轮询Redis库中的时效性数据，采用随机抽取的策略，利用过期数据占比的方式控制删除频度</p>
</li>
<li>
<p>特点1：CPU性能占用设置由峰值，检测频度可自定义设置</p>
</li>
<li>
<p>特点2：内存压力不是很大，长期占用内存的冷数据会被持续清理</p>
</li>
<li>
<p>总结：周期性抽查检查空间（随机抽查，重点抽查）</p>
</li>
</ul>
<h2 id="-49"><a class="markdownIt-Anchor" href="#-49"></a> <a href="#%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5%E6%AF%94%E5%AF%B9" title="删除策略比对"></a>删除策略比对</h2>
<table>
<thead>
<tr>
<th>删除策略</th>
<th>特点1</th>
<th>特点2</th>
<th>总结</th>
</tr>
</thead>
<tbody>
<tr>
<td>定期删除</td>
<td>节约内存，无占用</td>
<td>部分时段占用CPU资源，频度高</td>
<td>拿时间换空间</td>
</tr>
<tr>
<td>惰性删除</td>
<td>内存占用严重</td>
<td>延时执行，CPU利用率高</td>
<td>拿空间换时间</td>
</tr>
<tr>
<td>定期删除</td>
<td>内存定期随机清理</td>
<td>每秒花费固定的CPU资源维护内存</td>
<td>随机抽查，重点抽查</td>
</tr>
</tbody>
</table>
<h2 id="-50"><a class="markdownIt-Anchor" href="#-50"></a> <a href="#%E9%80%90%E5%87%BA%E7%AE%97%E6%B3%95" title="逐出算法"></a>逐出算法</h2>
<h3 id="-51"><a class="markdownIt-Anchor" href="#-51"></a> <a href="#%E6%96%B0%E6%95%B0%E6%8D%AE%E8%BF%9B%E5%85%A5%E6%A3%80%E6%B5%8B" title="新数据进入检测"></a>新数据进入检测</h3>
<ul>
<li>
<p>当新数据进入Redis时，如果内存不足怎么办？</p>
<ul>
<li>
<p>Redis使用内存存储数据，在执行每一个命令前，会调用<code>freeMemoryIfNeeded()</code>检测内存是否充足，如果内存不满足新加入数据的最低存储要求，Redis要临时删除一些数据为当前指令清除存储空间。清理数据的策略称为<strong>逐出算法</strong></p>
</li>
<li>
<p>注意：逐出算法的过程不是100%能够清理出足够的可使用的内存空间，如果不成功则反复执行。当对所有数据尝试完毕后，如果不能达到内存清理的要求，将出现错误信息</p>
<h3 id="-52"><a class="markdownIt-Anchor" href="#-52"></a> <a href="#%E5%BD%B1%E5%93%8D%E6%95%B0%E6%8D%AE%E9%80%90%E5%87%BA%E7%9A%84%E7%9B%B8%E5%85%B3%E8%AE%BE%E7%BD%AE" title="影响数据逐出的相关设置"></a>影响数据逐出的相关设置</h3>
</li>
</ul>
</li>
<li>
<p>最大可使用内存</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxmemory  </span><br></pre></td></tr></table></figure>
<p>占用物理内存的比例，默认值为0，表示不限制。生产环境中根据需求设定，通常设置在50%以上。</p>
</li>
<li>
<p>每次选取待删除数据的个数</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxmemory-samples  </span><br></pre></td></tr></table></figure>
<p>选取数据时并不会全库扫描，导致严重的性能消耗，降低读写性能。因此采用随机获取数据的方式作为待检测删除数据</p>
</li>
<li>
<p>删除策略</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxmemory-policy  </span><br></pre></td></tr></table></figure>
<p>达到最大内存后的，对被挑选出来的数据进行删除的策略</p>
</li>
<li>
<p>检测易失数据（可能会过期的数据集<code>server.db[i].expires</code>）</p>
<ol>
<li><code>volatile-lru</code>：挑选最近最少使用的数据淘汰（推荐）</li>
<li><code>volatile-lfu</code>：挑选最近使用次数最少的数据淘汰</li>
<li><code>volatile-ttl</code>：挑选将要过期的数据淘汰</li>
<li><code>volatile-random</code>：任意选择数据淘汰</li>
</ol>
</li>
<li>
<p>检测全库数据（所有数据集<code>server.db[i].dict</code>)</p>
<ol>
<li><code>allkeys-lru</code>：挑选最近最少使用的数据淘汰</li>
<li><code>allkeys-lfu</code>：挑选最近使用次数最少的数据淘汰</li>
<li><code>allkeys-random</code>：任意选择数据淘汰</li>
</ol>
</li>
<li>
<p>不使用数据驱逐</p>
<ul>
<li><code>no-enviction</code>(不驱逐)：禁止驱逐数据(redis4.0中默认策略)，会引发错误OOM(Out Of Memory)</li>
</ul>
</li>
<li>
<p>配置方式</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxmemory-policy volatile-lru  </span><br></pre></td></tr></table></figure>
<h3 id="-53"><a class="markdownIt-Anchor" href="#-53"></a> <a href="#%E6%95%B0%E6%8D%AE%E9%80%90%E5%87%BA%E7%AD%96%E7%95%A5%E9%85%8D%E7%BD%AE%E4%BE%9D%E6%8D%AE" title="数据逐出策略配置依据"></a>数据逐出策略配置依据</h3>
</li>
<li>
<p>使用<code>INFO</code>命令输出监控信息，查询缓存<code>hit</code>和<code>miss</code>的次数，根据业务需求调优Redis配置</p>
</li>
</ul>
<h1 id="-54"><a class="markdownIt-Anchor" href="#-54"></a> <a href="#Redis-Conf" title="Redis.Conf"></a>Redis.Conf</h1>
<h2 id="-55"><a class="markdownIt-Anchor" href="#-55"></a> <a href="#%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9F%BA%E7%A1%80%E9%85%8D%E7%BD%AE" title="服务器基础配置"></a>服务器基础配置</h2>
<ul>
<li>设置服务器以守护进程的方式运行：<code>daemonize yes|no</code></li>
<li>绑定主机地址：<code>bind 127.0.0.1</code></li>
<li>设置服务器端口号：<code>port 6379</code></li>
<li>设置数据库数量：<code>databases 16</code></li>
</ul>
<h2 id="-56"><a class="markdownIt-Anchor" href="#-56"></a> <a href="#%E6%97%A5%E5%BF%97%E9%85%8D%E7%BD%AE" title="日志配置"></a>日志配置</h2>
<ul>
<li>设置服务器以指定日志记录级别：<code>loglevel debug|verbose|notice|warning</code></li>
<li>日志记录文件名：<code>logfile 端口号.log</code></li>
</ul>
<p><strong>注意：日志级别开发期设置为<code>verbose</code>，生产环境中配置为<code>notice</code>，简化日志输出量，降低写日志IO的频度</strong></p>
<h2 id="-57"><a class="markdownIt-Anchor" href="#-57"></a> <a href="#%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE" title="客户端配置"></a>客户端配置</h2>
<ul>
<li>
<p>设置同一时间最大客户端连接数，默认无限制。当客户端连接到达上限，Redis会关闭新的连接</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxclient 0  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>客户端限制等待最长时长，达到最大值后关闭连接，如需要关闭该功能，设置为0</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">timeout</span> 300  </span><br></pre></td></tr></table></figure>
<h2 id="-58"><a class="markdownIt-Anchor" href="#-58"></a> <a href="#%E5%A4%9A%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BF%AB%E6%8D%B7%E9%85%8D%E7%BD%AE" title="多服务器快捷配置"></a>多服务器快捷配置</h2>
</li>
<li>
<p>导入并加载指定配置文件信息，用于快速创建Redis公共配置较多的Redis实例配置文件，便于维护</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">include /path/server-端口号.conf  </span><br></pre></td></tr></table></figure>
</li>
</ul>
<h1 id="-59"><a class="markdownIt-Anchor" href="#-59"></a> <a href="#%E9%AB%98%E7%BA%A7%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B" title="高级数据类型"></a>高级数据类型</h1>
<h2 id="-60"><a class="markdownIt-Anchor" href="#-60"></a> <a href="#Bitmaps" title="Bitmaps"></a>Bitmaps</h2>
<ul>
<li>
<p>获取指定key对应偏移量上的bit值</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">getbit key offset  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>设置指定key对应偏移量上的bit值，value只能时1或0</p>
<p>1</p>
<p>setbit key offset value</p>
</li>
<li>
<p>对指定key按位进行交、并、非、异或操作，并将结果保存到destKey中</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">bitop op destKey key1 \[key2...\]  </span><br><span class="line">// and：交  </span><br><span class="line">// or：并  </span><br><span class="line">// not：非  </span><br><span class="line">// xor：异或  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>统计指定key中1的数量</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bitcount key \[start end\]  </span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="-61"><a class="markdownIt-Anchor" href="#-61"></a> <a href="#HyperLogLog" title="HyperLogLog"></a>HyperLogLog</h2>
<ul>
<li>
<p>基数：数据集去重后元素个数</p>
</li>
<li>
<p>HyperLogLog是用来做基数统计的，运用了LogLog的算法</p>
</li>
<li>
<p>添加数据：<code>pfadd key element [element...]</code></p>
</li>
<li>
<p>统计数据：<code>pfcount key [key...]</code></p>
</li>
<li>
<p>合并数据：<code>pfmerge destKey sourceKey [sourceKey...]</code></p>
</li>
</ul>
<h3 id="-62"><a class="markdownIt-Anchor" href="#-62"></a> <a href="#%E8%AF%B4%E6%98%8E" title="说明"></a>说明</h3>
<ul>
<li>只用于进行基数统计，不是集合，不保存数据，只记录数量而不是具体数量</li>
<li>核心是基数估计算法，最终数值存在一定误差</li>
<li>误差范围：基数估计的结果是一个带有0.81%标准错误的近似值</li>
<li>耗空间极小，每个hyperloglog key占用了12K的内存用于标记基数</li>
<li><code>pfadd</code>命令不是一次性分配12K内存使用，会随着基数的增加内存主键增大</li>
<li><code>pfmerge</code>命令合并后占用的存储空间为12K，无论合并之前数据量多大</li>
</ul>
<h2 id="-63"><a class="markdownIt-Anchor" href="#-63"></a> <a href="#GEO" title="GEO"></a>GEO</h2>
<ul>
<li>
<p>存放地理位置的数据类型</p>
<h3 id="-64"><a class="markdownIt-Anchor" href="#-64"></a> <a href="#%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C-1" title="基本操作"></a>基本操作</h3>
</li>
<li>
<p>添加坐标点：<code>geoadd key longitude latitude member [longitude latitude member...]</code></p>
</li>
<li>
<p>获取坐标点：<code>geopos key member [member...]</code></p>
</li>
<li>
<p>计算坐标点距离：<code>getdist key member1 member2 [unit]</code>(unit是单位，<code>m=米 km=千米</code>)</p>
</li>
<li>
<p>根据坐标求范围内的数据</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">georadius key longitude latitude redius m|km|ft|mi \[withcoord\] \[withdist\] \[withhash\] \[count count\]  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>根据点求范围内的数据</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">georadiusbymember key member radius m|km|ft|mi \[withcoord\] \[withdist\] \[withhash\] \[count count\]  </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>获取指定点对应的坐标hash值</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">geohash key member \[member...\]</span><br></pre></td></tr></table></figure></li>
</ul>

    </div>

    
    
    

    <footer class="post-footer">







<div class="license">
  <div class="license-title">Redis进阶</div>
  <div class="license-link">
    <a href="https://blog.fantasyke.cn/posts/1297/">https://blog.fantasyke.cn/posts/1297/</a>
  </div>
  <div class="license-meta">
    <div class="license-meta-item">
      <div class="license-meta-title">本文作者</div>
      <div class="license-meta-text">
          Fantasy-ke
      </div>
    </div>
      <div class="license-meta-item">
        <div class="license-meta-title">发布于</div>
        <div class="license-meta-text">
          2023-05-30
        </div>
      </div>
      <div class="license-meta-item">
        <div class="license-meta-title">更新于</div>
        <div class="license-meta-text">
          2024-12-17
        </div>
      </div>
    <div class="license-meta-item">
      <div class="license-meta-title">许可协议</div>
      <div class="license-meta-text">
          禁止转载引用
      </div>
    </div>
  </div>
  <div class="license-statement">
      如需转载或引用本文，请先获得作者授权！
  </div>
</div>
          <div class="reward-container">
  <div>Buy me a coffee</div>
  <button>
    Donate
  </button>
  <div class="post-reward">
      <div>
        <img src="/images/wechatpay.png" alt="Fantasy-ke WeChat Pay">
        <span>WeChat Pay</span>
      </div>

  </div>
</div>

          <div class="followme">
  <span>Welcome to my other publishing channels</span>

  <div class="social-list">

      <div class="social-item">
          <a target="_blank" class="social-link" href="https://github.com/fantasy-ke">
            <span class="icon">
              <i class="fab fa-github"></i>
            </span>

            <span class="label">GitHub</span>
          </a>
      </div>
  </div>
</div>

          <div class="post-tags">
              <a href="/tags/Redis/" rel="tag"><i class="fa fa-tag"></i> Redis</a>
              <a href="/tags/NOSQL/" rel="tag"><i class="fa fa-tag"></i> NOSQL</a>
          </div>

        
  <div class="social-like a2a_kit a2a_kit_size_32 a2a_default_style">
    <a class="a2a_dd" target="_blank" rel="noopener" href="https://www.addtoany.com/share"></a>
      <a class="a2a_button_facebook"></a>
      <a class="a2a_button_twitter"></a>
      <a class="a2a_button_telegram"></a>
      <a class="a2a_button_wechat"></a>
  </div>

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/posts/4509/" rel="prev" title="Redis集群">
                  <i class="fa fa-angle-left"></i> Redis集群
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/posts/26216/" rel="next" title="Redis基础">
                  Redis基础 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






    <div class="comments gitalk-container"></div>
</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2021 – 
    <span itemprop="copyrightYear">2024</span>
    <span class="with-love">
      <i class="fa fa-solid fa-t-rex"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">Fantasy-ke</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>Word count total: </span>
    <span title="Word count total">72k</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>Reading time total &asymp;</span>
    <span title="Reading time total">4:21</span>
  </span>
</div>
<div class="busuanzi-count">
    <span class="post-meta-item" id="busuanzi_container_site_uv">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="Total Visitors">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-item" id="busuanzi_container_site_pv">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="Total Views">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div> 
<script src="https://cdn.jsdelivr.net/npm/moment@2.22.2/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment-precise-range-plugin@1.3.0/moment-precise-range.min.js"></script>
<script>
  var now = new Date();
  function timer() {
    var grt= new Date("03/12/2022 13:14:21");//此处修改你的建站时间或者网站上线时间
    now.setTime(now.getTime()+250);
    days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
    hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours);
    if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
    mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;}
    seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
    snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;}
    var ages = `${dnum}天${hnum}小时${mnum}分${snum}秒`;
    div.innerHTML = `本站已安全运行 ${ages} 🐶`;
  }
  var div = document.createElement("div");
  //插入到copyright之后
  var copyright = document.querySelector(".busuanzi-count");
  document.querySelector(".footer-inner").insertBefore(div, copyright.nextSibling);
  timer();
  setInterval("timer()",1000)
</script>


<div class="footer-menu">
    <a style="color: chocolate;" href="/tags/">文章标签</a> · <a style="color: chocolate;"  href="/policy/">网站政策</a> · <a style="color: chocolate;"  href="/photos/">文章相册</a>
</div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="Back to top">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>
  <a role="button" class="book-mark-link book-mark-link-fixed"></a>

  <span class="exturl github-corner" data-url="aHR0cHM6Ly9naXRodWIuY29tL2ZhbnRhc3kta2U=" title="Follow me on GitHub" aria-label="Follow me on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></span>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.31/fancybox/fancybox.umd.js" integrity="sha256-a+H7FYzJv6oU2hfsfDGM2Ohw/cR9v+hPfxHCLdmCrE8=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/sidebar.js"></script><script src="/js/next-boot.js"></script><script src="/js/bookmark.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>


  <script src="/js/third-party/addtoany.js"></script>

  
  <script data-pjax async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>




<script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.5.7/lib/darkmode-js.min.js"></script>

<script>
var options = {
  bottom: '64px',
  right: 'unset',
  left: '32px',
  time: '0.5s',
  mixColor: 'transparent',
  backgroundColor: 'transparent',
  buttonColorDark: '#100f2c',
  buttonColorLight: '#fff',
  saveInCookies: true,
  label: '🌓',
  autoMatchOsTheme: true
}
const darkmode = new Darkmode(options);
window.darkmode = darkmode;
darkmode.showWidget();
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/gitalk/1.8.0/gitalk.css" integrity="sha256-AJnUHL7dBv6PGaeyPQJcgQPDjt/Hn/PvYZde1iqfp8U=" crossorigin="anonymous">

<script class="next-config" data-name="gitalk" type="application/json">{"enable":true,"github_id":"fantasy-ke","repo":"fantasy-ke.github.io","client_id":"Ov23li8eCFrhnzfiGx5T","client_secret":"ce23581c2059392ebd00afd08d5ba43f767fd1b1","admin_user":"fantasy-ke","distraction_free_mode":true,"proxy":"https://cors-anywhere.azm.workers.dev/https://github.com/login/oauth/access_token","language":"zh-CN","labels":"gitalk","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/gitalk/1.8.0/gitalk.min.js","integrity":"sha256-MVK9MGD/XJaGyIghSVrONSnoXoGh3IFxLw0zfvzpxR4="},"path_md5":"444c24642dad5bbc9e2096c93e267eff"}</script>
<script src="/js/third-party/comments/gitalk.js"></script>


<script src="/js/minigrid.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script data-pjax type="text/javascript">
var album = document.querySelector(".album");
if (album) {
  // 相册列表 JSON 数据
  var imgDataPath = album.getAttribute('json-src');
  // 照片存储路径
  var imgPath = album.getAttribute('photo-src');
  // 最多显示数量
  var imgMaxNum = 50;
  // 获取窗口大小以决定图片宽度
  var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  var imageWidth;

  if (windowWidth < 768) {
    imageWidth = 145; // 移动端图片宽度
  } else {
    imageWidth = 235;
  }

  // 生成相册
  var linkDataPath = imgDataPath;
  var photo = {
    page: 1,
    offset: imgMaxNum,
    init: function () {
      var that = this;
      $.getJSON(linkDataPath, function (data) {
          that.render(that.page, data);
      });
    },
    render: function (page, data) {
      var begin = (page - 1) * this.offset;
      var end = page * this.offset;
      if (begin >= data.length) return;
      var imgNameWithPattern, imgName, imageSize, imageX, imageY, li = "";
      for (var i = begin; i < end && i < data.length; i++) {
        imgNameWithPattern = data[i].path;
        imgName = data[i].name;
        imageSize = data[i].size;
        li += '<div class="card" style="width:' + imageWidth + 'px" >';
        li += '<div class="album-photo" style="height:' + imageWidth + 'px" >';
        li += '<a class="fancybox fancybox.image" href="' + imgPath + imgNameWithPattern + '" itemscope="" itemtype="http://schema.org/ImageObject" itemprop="url" data-fancybox="group" rel="group" data-caption="' + imgName + '" title="' +  imgName + '">';
        li += '<img data-src="' + imgPath + imgNameWithPattern + '" src="' + imgPath + imgNameWithPattern + '" alt="' +  imgName + '" data-loaded="true">';
        li += '</a>';
        li += '</div>';
        li += '</div>';
      }
      album.insertAdjacentHTML('beforeend', li);
      this.minigrid();
    },
    minigrid: function () {
      var grid = new Minigrid({
        container: '.album',
        item: '.card',
        gutter: 12
      });
      grid.mount();
      window.addEventListener('resize', function () {
        grid.mount();
      });
    }
  };
  photo.init();
}
</script>
<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"model":{"jsonPath":"/live2dw/assets/hijiki.model.json"},"display":{"position":"right","width":170,"height":330},"mobile":{"show":true},"react":{"opacity":0.7},"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>
